package com.sunyard.manage.handler;

import com.auth0.jwt.exceptions.JWTCreationException;
import com.google.common.base.VerifyException;
import com.sunyard.beanvalidator.BeanValidators;
import com.sunyard.constant.ErrMessageConst;
import com.sunyard.constant.manage.CodeConst;
import com.sunyard.constant.manage.CommonConst;
import com.sunyard.exception.AuditFalseException;
import com.sunyard.exception.IllegalOperationException;
import com.sunyard.utils.Response.BaseResult;
import com.sunyard.utils.Response.GetResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.ServletException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.nio.file.AccessDeniedException;
import java.sql.SQLException;
import java.sql.SQLSyntaxErrorException;
import java.util.List;
import java.util.Set;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {


    @ExceptionHandler(value = {ServletException.class})
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public BaseResult handleBadRequestException(Exception e) {
        log.warn("GlobalExceptionHandler.handleBadRequestException", e);
        if (e instanceof HttpRequestMethodNotSupportedException) {
            return GetResult.getResultErr("当前方法不支持" + ((HttpRequestMethodNotSupportedException) e).getMethod() + "请求");
        } else if (e instanceof HttpMediaTypeNotSupportedException) {
            return GetResult.getResultErr("当前方法的contentType不支持" + ((HttpMediaTypeNotSupportedException) e).getContentType());
        }
        return GetResult.getResultErr();

    }


    @ExceptionHandler(value = {IllegalOperationException.class})
    @ResponseStatus(value = HttpStatus.OK)
    public BaseResult handleIllegalOperationException(IllegalOperationException e) {
        log.error("GlobalExceptionHandler.handleIllegalOperationException, message:", e);
        return GetResult.getResultFail(e.getMessage());
    }

    @ExceptionHandler(value = {HttpMessageNotReadableException.class, BindException.class, MethodArgumentNotValidException.class,
            ConstraintViolationException.class, MissingServletRequestParameterException.class, IllegalArgumentException.class})
    @ResponseStatus(value = HttpStatus.OK)
    public BaseResult handleParamValidException(Exception e) {
        log.warn("GlobalExceptionHandler.handleParamValidException", e);
        if (e instanceof BindException) {
            return GetResult.getResultFail(((BindException) e).getAllErrors().get(0).getDefaultMessage());
        } else if (e instanceof MethodArgumentNotValidException) {
            return GetResult.getResultFail(((MethodArgumentNotValidException) e).getBindingResult().getAllErrors().get(0).getDefaultMessage());
        } else if (e instanceof ConstraintViolationException) {
            ConstraintViolationException cve = ((ConstraintViolationException) e);
            Set<ConstraintViolation<?>> constraintViolations = cve.getConstraintViolations();
            if (CollectionUtils.isNotEmpty(constraintViolations)) {
                for (ConstraintViolation<?> c : constraintViolations) {
                    return GetResult.getResultFail(c.getMessage());
                }
            }
        } else if (e instanceof MissingServletRequestParameterException) {
            return GetResult.getResultFail(e.getMessage());
        } else if (e instanceof HttpMessageNotReadableException) {
            return GetResult.getResultFail("参数异常,请检查输入值的范围。");
        }
        return GetResult.getResultFail(ErrMessageConst.PARAM_ERROR);
    }


    @ExceptionHandler(value = AccessDeniedException.class)
    @ResponseStatus(value = HttpStatus.FORBIDDEN)
    public BaseResult handleAccessDeniedException(AccessDeniedException e) {
        log.warn("GlobalExceptionHandler.handleAccessDeniedException, msg:{}", ExceptionUtils.getRootCauseMessage(e));
        return GetResult.getResultFail(ErrMessageConst.FORBIDDEN);
    }

    /**
     * SQL校验
     */
    @ExceptionHandler(value = {SQLException.class, BadSqlGrammarException.class})
    @ResponseStatus(value = HttpStatus.OK)
    public BaseResult handleSqlException(Exception e) {
        log.error(ErrMessageConst.SQL_EXCEPTION, e);
        return GetResult.getResultFail(ErrMessageConst.SQL_EXCEPTION);
    }

    /**
     * SQL校验
     */
    @ExceptionHandler(value = {JWTCreationException.class})
    @ResponseStatus(value = HttpStatus.OK)
    public BaseResult<String> handleJWTCreationException(Exception e) {
        log.error(ErrMessageConst.JWT_EXCEPTION, e);
        return GetResult.getResultFail(ErrMessageConst.JWT_EXCEPTION);
    }

    /**
     * /
     * SQL校验
     */
    @ExceptionHandler(value = {NullPointerException.class})
    @ResponseStatus(value = HttpStatus.OK)
    public BaseResult<String> handleNullPointerException(Exception e) {
        log.error(ErrMessageConst.NULL_EXCEPTION, e);
        if (StringUtils.isBlank(e.getMessage())) {
            return GetResult.getResultErr();
        }
        return GetResult.getResultFail(e.getMessage());
    }

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(value = HttpStatus.OK)
    public BaseResult<String> handleException(Exception e) {
        log.error(ErrMessageConst.UN_EXCEPTION, e);
        return GetResult.getResultErr(ErrMessageConst.UN_EXCEPTION);
    }

    @ExceptionHandler(value = {AuditFalseException.class})
    @ResponseStatus(value = HttpStatus.OK)
    public BaseResult<String> handleAuditFalseException(Exception e) {
        return GetResult.getResultSuccess(e.getMessage());
    }

}
